package com.thz.common.utils;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import com.thz.common.enums.ErrorCode;
import com.thz.common.exception.BusinessException;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

/**
 * 文件工具类
 * 
 * @author THZ
 * @date 2025
 */
public class FileUtils {
    
    /**
     * 允许上传的视频文件扩展名
     */
    private static final List<String> ALLOWED_VIDEO_EXTENSIONS = Arrays.asList(
            "mp4", "avi", "mov", "wmv", "flv", "mkv", "webm", "m4v", "mpeg", "mpg"
    );
    
    /**
     * 允许的视频 MIME 类型
     */
    private static final List<String> ALLOWED_VIDEO_MIME_TYPES = Arrays.asList(
            "video/mp4",
            "video/x-msvideo",      // avi
            "video/quicktime",      // mov
            "video/x-ms-wmv",       // wmv
            "video/x-flv",          // flv
            "video/x-matroska",     // mkv
            "video/webm",           // webm
            "video/x-m4v",          // m4v
            "video/mpeg",           // mpeg/mpg
            "application/octet-stream"  // 某些视频文件可能被识别为这个类型
    );
    
    /**
     * 允许上传的头像文件扩展名
     */
    private static final List<String> ALLOWED_AVATAR_EXTENSIONS = Arrays.asList(
            "jpg", "jpeg", "png", "gif", "webp", "svg"
    );
    
    /**
     * 允许的头像 MIME 类型
     */
    private static final List<String> ALLOWED_AVATAR_MIME_TYPES = Arrays.asList(
            "image/jpeg",
            "image/jpg",
            "image/png",
            "image/gif",
            "image/webp",
            "image/svg+xml"
    );
    
    /**
     * 允许转换为SVG的图像文件扩展名
     */
    private static final List<String> ALLOWED_IMAGE_TO_SVG_EXTENSIONS = Arrays.asList(
            "jpg", "jpeg", "png", "gif", "bmp", "webp", "tiff", "tif"
    );
    
    /**
     * 允许转换为SVG的图像 MIME 类型
     */
    private static final List<String> ALLOWED_IMAGE_TO_SVG_MIME_TYPES = Arrays.asList(
            "image/jpeg",
            "image/jpg",
            "image/png",
            "image/gif",
            "image/bmp",
            "image/webp",
            "image/tiff",
            "image/x-ms-bmp"
    );

    /**
     * 允许进行文档转PDF的扩展名
     */
    private static final List<String> ALLOWED_DOC_TO_PDF_EXTENSIONS = Arrays.asList(
            "docx", "doc", "odt", "rtf"
    );

    /**
     * 允许的文档 MIME 类型
     */
    private static final List<String> ALLOWED_DOC_TO_PDF_MIME_TYPES = Arrays.asList(
            "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
            "application/msword",
            "application/vnd.oasis.opendocument.text",
            "text/rtf",
            "application/rtf",
            "application/octet-stream"
    );
    
    /**
     * 最大图像文件大小：20MB
     */
    private static final long MAX_IMAGE_SIZE = 20 * 1024 * 1024;

    /**
     * 最大文档文件大小：30MB
     */
    private static final long MAX_DOCUMENT_SIZE = 30 * 1024 * 1024;
    
    /**
     * 最大文件大小：100MB（视频文件）
     */
    private static final long MAX_FILE_SIZE = 100 * 1024 * 1024;
    
    /**
     * 最大头像文件大小：5MB
     */
    private static final long MAX_AVATAR_SIZE = 5 * 1024 * 1024;
    
    /**
     * 验证上传的视频文件
     * 
     * @param file 上传的文件
     * @throws BusinessException 如果文件不合法
     */
    public static void validateVideoFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new BusinessException(ErrorCode.FILE_EMPTY);
        }
        
        // 1. 检查文件大小
        if (file.getSize() > MAX_FILE_SIZE) {
            throw new BusinessException(ErrorCode.FILE_SIZE_EXCEED);
        }
        
        // 2. 检查文件名
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null || originalFilename.isEmpty()) {
            throw new BusinessException(ErrorCode.FILE_NAME_EMPTY);
        }
        
        // 3. 检查文件扩展名
        String extension = getFileExtension(originalFilename);
        if (extension.isEmpty()) {
            throw new BusinessException(ErrorCode.FILE_NO_EXTENSION);
        }
        
        if (!ALLOWED_VIDEO_EXTENSIONS.contains(extension.toLowerCase())) {
            throw new BusinessException(ErrorCode.FILE_FORMAT_NOT_SUPPORTED, 
                    "不支持 ." + extension + " 格式，仅支持 " + String.join(", ", ALLOWED_VIDEO_EXTENSIONS));
        }
        
        // 4. 检查 MIME 类型（双重验证）
        String contentType = file.getContentType();
        if (contentType == null || contentType.isEmpty()) {
            throw new BusinessException(ErrorCode.FILE_TYPE_INVALID);
        }
        
        // MIME 类型必须以 video/ 开头或者是允许的类型
        boolean isMimeValid = contentType.startsWith("video/") || 
                             ALLOWED_VIDEO_MIME_TYPES.contains(contentType.toLowerCase());
        
        if (!isMimeValid) {
            throw new BusinessException(ErrorCode.FILE_MIME_TYPE_INVALID, 
                    "文件类型 " + contentType + " 不是有效的视频格式");
        }
    }

    /**
     * 验证上传的文档文件（DOC/DOCX/ODT/RTF）
     *
     * @param file 上传的文件
     */
    public static void validateDocumentFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new BusinessException(ErrorCode.FILE_EMPTY);
        }

        if (file.getSize() > MAX_DOCUMENT_SIZE) {
            throw new BusinessException(ErrorCode.FILE_SIZE_EXCEED, "文档大小不能超过30MB");
        }

        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null || originalFilename.isEmpty()) {
            throw new BusinessException(ErrorCode.FILE_NAME_EMPTY);
        }

        String extension = getFileExtension(originalFilename);
        if (extension.isEmpty()) {
            throw new BusinessException(ErrorCode.FILE_NO_EXTENSION);
        }

        if (!ALLOWED_DOC_TO_PDF_EXTENSIONS.contains(extension.toLowerCase())) {
            throw new BusinessException(ErrorCode.FILE_FORMAT_NOT_SUPPORTED,
                    "仅支持 DOC、DOCX、ODT、RTF 文档");
        }

        String contentType = file.getContentType();
        if (contentType == null || contentType.isEmpty()) {
            throw new BusinessException(ErrorCode.FILE_TYPE_INVALID);
        }

        if (!ALLOWED_DOC_TO_PDF_MIME_TYPES.contains(contentType.toLowerCase())) {
            throw new BusinessException(ErrorCode.FILE_MIME_TYPE_INVALID,
                    "文件类型不是有效的文档格式");
        }
    }
    
    /**
     * 获取文件扩展名
     * 
     * @param filename 文件名
     * @return 扩展名（不带点）
     */
    public static String getFileExtension(String filename) {
        if (filename == null || filename.isEmpty()) {
            return "";
        }
        int lastDotIndex = filename.lastIndexOf('.');
        if (lastDotIndex > 0 && lastDotIndex < filename.length() - 1) {
            return filename.substring(lastDotIndex + 1);
        }
        return "";
    }
    
    /**
     * 生成唯一的文件名
     * 
     * @param originalFilename 原始文件名
     * @return 新的文件名
     */
    public static String generateUniqueFilename(String originalFilename) {
        String extension = getFileExtension(originalFilename);
        return IdUtil.simpleUUID() + "." + extension;
    }
    
    /**
     * 保存上传的文件
     * 
     * @param file 上传的文件
     * @param uploadDir 上传目录
     * @return 保存后的文件对象
     * @throws BusinessException 如果保存失败
     */
    public static File saveUploadFile(MultipartFile file, String uploadDir) {
        try {
            // 统一将目录解析为绝对路径，避免在相对路径时被解析到临时目录
            File dir = new File(uploadDir);
            if (!dir.isAbsolute()) {
                dir = new File(System.getProperty("user.dir"), uploadDir);
            }
            if (!dir.exists()) {
                dir.mkdirs();
            }
            
            // 生成唯一文件名
            String uniqueFilename = generateUniqueFilename(file.getOriginalFilename());
            File destFile = new File(dir, uniqueFilename);
            
            // 保存文件
            file.transferTo(destFile);
            return destFile;
        } catch (IOException e) {
            throw new BusinessException(ErrorCode.FILE_SAVE_FAILED, e.getMessage(), e);
        }
    }
    
    /**
     * 删除文件
     * 
     * @param filePath 文件路径
     */
    public static void deleteFile(String filePath) {
        if (filePath != null && !filePath.isEmpty()) {
            FileUtil.del(filePath);
        }
    }
    
    /**
     * 验证上传的头像文件
     * 
     * @param file 上传的文件
     * @throws BusinessException 如果文件不合法
     */
    public static void validateAvatarFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new BusinessException(ErrorCode.FILE_EMPTY);
        }
        
        // 1. 检查文件大小
        if (file.getSize() > MAX_AVATAR_SIZE) {
            throw new BusinessException(ErrorCode.FILE_SIZE_EXCEED, "头像文件大小不能超过5MB");
        }
        
        // 2. 检查文件名
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null || originalFilename.isEmpty()) {
            throw new BusinessException(ErrorCode.FILE_NAME_EMPTY);
        }
        
        // 3. 检查文件扩展名
        String extension = getFileExtension(originalFilename);
        if (extension.isEmpty()) {
            throw new BusinessException(ErrorCode.FILE_NO_EXTENSION);
        }
        
        if (!ALLOWED_AVATAR_EXTENSIONS.contains(extension.toLowerCase())) {
            throw new BusinessException(ErrorCode.FILE_FORMAT_NOT_SUPPORTED, 
                    "不支持的头像格式 ." + extension + "，仅支持 " + String.join(", ", ALLOWED_AVATAR_EXTENSIONS));
        }
        
        // 4. 检查 MIME 类型
        String contentType = file.getContentType();
        if (contentType == null || contentType.isEmpty()) {
            throw new BusinessException(ErrorCode.FILE_TYPE_INVALID);
        }
        
        // MIME 类型必须是图片类型
        boolean isMimeValid = contentType.startsWith("image/") && 
                             ALLOWED_AVATAR_MIME_TYPES.contains(contentType.toLowerCase());
        
        if (!isMimeValid) {
            throw new BusinessException(ErrorCode.FILE_MIME_TYPE_INVALID);
        }
    }
    
    /**
     * 验证上传的图像文件（用于转换为SVG）
     * 
     * @param file 上传的文件
     * @throws BusinessException 如果文件不合法
     */
    public static void validateImageFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new BusinessException(ErrorCode.FILE_EMPTY);
        }
        
        // 1. 检查文件大小
        if (file.getSize() > MAX_IMAGE_SIZE) {
            throw new BusinessException(ErrorCode.FILE_SIZE_EXCEED, "图像文件大小不能超过20MB");
        }
        
        // 2. 检查文件名
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null || originalFilename.isEmpty()) {
            throw new BusinessException(ErrorCode.FILE_NAME_EMPTY);
        }
        
        // 3. 检查文件扩展名
        String extension = getFileExtension(originalFilename);
        if (extension.isEmpty()) {
            throw new BusinessException(ErrorCode.FILE_NO_EXTENSION);
        }
        
        if (!ALLOWED_IMAGE_TO_SVG_EXTENSIONS.contains(extension.toLowerCase())) {
            throw new BusinessException(ErrorCode.FILE_FORMAT_NOT_SUPPORTED, 
                    "不支持的图像格式 ." + extension + "，仅支持 " + String.join(", ", ALLOWED_IMAGE_TO_SVG_EXTENSIONS));
        }
        
        // 4. 检查 MIME 类型
        String contentType = file.getContentType();
        if (contentType == null || contentType.isEmpty()) {
            throw new BusinessException(ErrorCode.FILE_TYPE_INVALID);
        }
        
        // MIME 类型必须是图片类型
        boolean isMimeValid = contentType.startsWith("image/") && 
                             ALLOWED_IMAGE_TO_SVG_MIME_TYPES.contains(contentType.toLowerCase());
        
        if (!isMimeValid) {
            throw new BusinessException(ErrorCode.FILE_MIME_TYPE_INVALID, 
                    "文件类型 " + contentType + " 不是有效的图片格式");
        }
    }
    
    /**
     * 格式化文件大小
     * 
     * @param size 文件大小（字节）
     * @return 格式化后的字符串
     */
    public static String formatFileSize(long size) {
        if (size < 1024) {
            return size + " B";
        } else if (size < 1024 * 1024) {
            return String.format("%.2f KB", size / 1024.0);
        } else if (size < 1024 * 1024 * 1024) {
            return String.format("%.2f MB", size / (1024.0 * 1024));
        } else {
            return String.format("%.2f GB", size / (1024.0 * 1024 * 1024));
        }
    }

    /**
     * 获取不包含扩展名的文件名
     *
     * @param filename 文件名
     * @return 不包含扩展名的部分
     */
    public static String getFileBaseName(String filename) {
        if (filename == null || filename.isEmpty()) {
            return "";
        }
        int lastDotIndex = filename.lastIndexOf('.');
        if (lastDotIndex > 0) {
            return filename.substring(0, lastDotIndex);
        }
        return filename;
    }

    /**
     * 对文件名进行简单的安全清理，只保留常见字符
     *
     * @param filename 原始文件名
     * @return 清理后的文件名
     */
    public static String sanitizeFilename(String filename) {
        if (filename == null) {
            return "";
        }
        return filename.replaceAll("[^a-zA-Z0-9-_\\.]", "_");
    }
}


